package com.amtf.datafile2.core.txt;

import java.util.ArrayList;
import java.util.List;

import com.amtf.datafile2.DataException;
import com.amtf.datafile2.DataField;
import com.amtf.datafile2.DataRecord;
import com.amtf.datafile2.cfg.txt.TxtDataTableDefinition;
import com.amtf.datafile2.cfg.txt.TxtDataTableDefinition.PARSE_MODE;
import com.amtf.datafile2.core.std.StdDataRecord;

public class TxtDataRecord extends StdDataRecord<TxtDataTableDefinition> {

	public TxtDataRecord(TxtDataTableDefinition definition) {
		super(definition);
	}

	public void validate() {
		this.clearErrors();

		if (definition.getFieldCount() != fields.length) {
			String msg = "Column count not match! Actual count:" + fields.length + ". Definition count:" + definition.getFieldCount();
			// String msg = "エラー内容：項目数が定義と異なります。　データ:" + fieldValues.length + " 定義:" + columnDefinition.length;
			appendError(msg);
		}

		for (int i = 0; i < fields.length; i++) {
			DataField field = fields[i];
			field.validate();
			if (field.isInvalid()) {
				// this.appendError("Column:" + (i + 1) + " [" + field.getDefinition().getName() + "] " + field.getErrors());
				this.appendError("Column:" + (i + 1) + " " + field.getErrors());
			}
		}
	}

	public String[] getValues() {
		String[] values = new String[fields.length];
		for (int i = 0; i < fields.length; i++) {
			values[i] = fields[i].getValue();
		}
		return values;
	}

	public String toValue(char delimiter) {
		StringBuffer content = new StringBuffer();

		if (fields.length > 0) {
			int max = fields.length - 1;
			for (int i = 0; i < max; i++) {
				if (fields[i] != null) {
					content.append(fields[i].getValue());
				} else {
					content.append("");
				}
				content.append(delimiter);
			}

			if (fields[max] != null) {
				content.append(fields[max].getValue());
			} else {
				content.append("");
			}
		}

		return content.toString();
	}

	public String toValue() {
		return toValue(definition.getFieldDelimiter());
	}

	public String toString(char delimiter) {
		StringBuffer content = new StringBuffer();

		if (fields.length > 0) {
			int max = fields.length - 1;
			for (int i = 0; i < max; i++) {
				if (fields[i] != null) {
					content.append(fields[i].toString());
				} else {
					content.append("");
				}
				content.append(delimiter);
			}

			if (fields[max] != null) {
				content.append(fields[max].toString());
			} else {
				content.append("");
			}
		}

		return content.toString();
	}

	public String toString() {
		return toString(definition.getFieldDelimiter());
	}

	// public static String toString(DataRecord record, TxtDataRecordDefinition definition) {
	// StringBuffer content = new StringBuffer();
	// char delimiter = definition.getFieldDelimiter();
	// DataField[] fields = record.getFields();
	// if (fields.length > 0) {
	// int max = fields.length - 1;
	// for (int i = 0; i < max; i++) {
	// if (fields[i] != null) {
	// content.append(TxtDataField.toString(fields[i], definition.getFieldDefinition(i)));
	// } else {
	// content.append("");
	// }
	// content.append(delimiter);
	// }
	//
	// if (fields[max] != null) {
	// content.append(TxtDataField.toString(fields[max], definition.getFieldDefinition(max)));
	// } else {
	// content.append("");
	// }
	// }
	//
	// return content.toString();
	// }

	// public static TxtDataRecord copyFields(TxtDataRecordDefinition definition, DataRecord row) {
	// TxtDataRecord record = definition.newDataRecordInstance();
	// record.append(field)
	// return record;
	// }

	public static TxtDataRecord copyValues(TxtDataTableDefinition definition, DataRecord fromrow) {
		if (definition.getFieldCount() == 0) {
			definition.addFields(fromrow.getFieldCount());
		}
		TxtDataRecord record = definition.newDataRecordInstance();
		record.set(fromrow.getValues());
		return record;
	}

	public static TxtDataRecord parseRecord(TxtDataTableDefinition definition, String row) throws DataException {
		String[] fieldValues = split(row, definition.getFieldDelimiter(), definition.getSmartQuote(), false);

		// int colcount = definition.getFieldDefinitions().size();
		// if (colcount != 0 && colcount != fieldValues.length) {
		// fieldValues = split(row, definition.getFieldDelimiter(), definition.getSmartQuote(), true);
		// }

		return parseRecord(definition, fieldValues);
	}

	public static TxtDataRecord parseRecord(TxtDataTableDefinition definition, Object[] fieldValues) throws DataException {

		String[] strrecord = new String[fieldValues.length];
		for (int i = 0; i < fieldValues.length; i++) {
			if (fieldValues[i] != null) {
				strrecord[i] = fieldValues[i].toString();
			} else {
				strrecord[i] = "";
			}
		}

		return parseRecord(definition, strrecord);
	}

	public static TxtDataRecord parseRecord(TxtDataTableDefinition definition, String[] fieldValues) throws DataException {
		if (definition.getFieldCount() == 0) {
			definition.addFields(fieldValues.length);
		}

		if (definition.getParseMode() == PARSE_MODE.SOURCE_PRIORITY) {
			for (int i = 0; i < fieldValues.length - definition.getFieldCount(); i++) {
				definition.addField();
			}
		}

		TxtDataRecord record = definition.newDataRecordInstance();
		record.set(fieldValues);
		return record;
	}

	public static String[] split(String row, char delimiter, char quote, boolean groupQuote) throws DataException {
		int beginIndex, endIndex;
		List<String> strs = new ArrayList<String>();

		int length = row.length();
		if (length > 0) {
			if (quote != ' ') {
				beginIndex = 0;
				int[] indexs = null;
				do {
					indexs = indexOfField(row, length, beginIndex, delimiter, quote, groupQuote);
					strs.add(row.substring(indexs[0], indexs[1]));
					beginIndex = indexs[2];
				} while (beginIndex < length);

				if (row.charAt(length - 1) == delimiter) {
					strs.add("");
				}
			} else {
				beginIndex = 0;
				endIndex = row.indexOf(delimiter);
				while (endIndex != -1) {
					strs.add(row.substring(beginIndex, endIndex));
					beginIndex = endIndex + 1;
					endIndex = row.indexOf(delimiter, beginIndex);
				}
				strs.add(row.substring(beginIndex, row.length()));
			}
		}

		String[] result = new String[strs.size()];
		strs.toArray(result);
		return result;
	}

	private static int[] indexOfField(String row, int length, int beginIndex, char delimiter, char quote, boolean groupQuote) throws DataException {
		int[] indexs = new int[3];
		int endIndex = 0;
		int index = beginIndex;
		int j;
		char c;
		// get the first not empty char
		while (true) {
			c = row.charAt(index);
			if (c == ' ') {
				if (++index >= length) {
					indexs[0] = beginIndex;
					indexs[1] = length;
					indexs[2] = length;
					return indexs;
				}

				continue;
			} else {
				break;
			}
		}

		if (c == delimiter) {
			indexs[0] = beginIndex;
			indexs[1] = index;
			indexs[2] = index + 1;
		} else if (c == quote) {
			if (groupQuote) {
				int quoteOffset = index;
				int quoteEndIndex = 0;
				int floor = 1;
				boolean isfieldEnd = false;
				while (!isfieldEnd) {
					do {
						quoteEndIndex = row.indexOf(quote, quoteOffset + 1);
						// not found
						if (quoteEndIndex == -1) {
							quoteEndIndex = length - 1;
							break;
						}
						//
						quoteOffset = quoteEndIndex;
					} while (--floor != 0);

					j = quoteEndIndex;
					// get the first not empty char
					while (true) {
						if (++j >= length) {
							indexs[0] = index;
							indexs[1] = quoteEndIndex + 1;
							indexs[2] = length;
							return indexs;
						}

						c = row.charAt(j);
						if (c == ' ') {
							continue;
						} else {
							break;
						}
					}

					if (c == delimiter) {
						isfieldEnd = true;
						indexs[0] = index;
						indexs[1] = quoteEndIndex + 1;
						indexs[2] = j + 1;
					} else {
						floor = 2;
						quoteOffset = j - 1;
					}
				}
			} else {
				int quoteOffset = index;
				int quoteEndIndex = 0;
				boolean isfieldEnd = false;
				while (!isfieldEnd) {
					quoteEndIndex = row.indexOf(quote, quoteOffset + 1);
					// not found
					if (quoteEndIndex == -1) {
						quoteEndIndex = length - 1;
					}

					j = quoteEndIndex;
					// get the first not empty char
					while (true) {
						if (++j >= length) {
							indexs[0] = index;
							indexs[1] = quoteEndIndex + 1;
							indexs[2] = length;
							return indexs;
						}

						c = row.charAt(j);
						if (c == ' ') {
							continue;
						} else {
							break;
						}
					}

					if (c == delimiter) {
						isfieldEnd = true;
						indexs[0] = index;
						indexs[1] = quoteEndIndex + 1;
						indexs[2] = j + 1;
					} else {
						quoteOffset = j - 1;
					}
				}
			}
		} else {
			endIndex = row.indexOf(delimiter, index + 1);
			if (endIndex != -1) {
				indexs[0] = beginIndex;
				indexs[1] = endIndex;
				indexs[2] = endIndex + 1;
			} else {
				indexs[0] = beginIndex;
				indexs[1] = length;
				indexs[2] = length;
			}
		}

		return indexs;
	}

}
